#include <systemc>
#include <iostream>

class PointStruct{ //{{{
public:
  PointStruct() : x_crd(0), y_crd(0), z_crd(0) {
    for (int i = 0; i < 6; ++i) {
      feature[i] = 0;
    }
  }
  PointStruct(sc_dt::sc_uint<16> x, sc_dt::sc_uint<16> y, sc_dt::sc_uint<8> z)
    : x_crd(x), y_crd(y), z_crd(z) {
    for (int i = 0; i < 6; i++) {
      feature[i] = 0;
    }
  }

  sc_dt::sc_uint<16> getX() const { return x_crd; }
  sc_dt::sc_uint<16> getY() const { return y_crd; }
  sc_dt::sc_uint<8>  getZ() const { return z_crd; }
  
  void setX(sc_dt::sc_uint<16> x) { x_crd = x; }
  void setY(sc_dt::sc_uint<16> y) { y_crd = y; }
  void setZ(sc_dt::sc_uint<8>  z) { z_crd = z; }

  sc_dt::sc_uint<16> getFeature(int idx) const {
    if (idx >= 0 && idx < 6) return feature[idx];
    throw std::out_of_range("Index out of range");
  }

  void setFeature(int idx, sc_dt::sc_uint<16> value) {
    if (idx >= 0 && idx < 6) feature[idx] = value;
    else throw std::out_of_range("Index out of range");
  }

  void print() const {
    std::cout << "Point coordinates: ("
              << x_crd.to_uint() << ", "
              << y_crd.to_uint() << ", "
              << z_crd.to_uint() << ")" << std::endl;

    std::cout << "Features: ";
    for (int i = 0; i < 6; ++i) {
      std::cout << feature[i].to_uint();
      if (i < 5) std::cout << ", ";
    }
    std::cout << std::endl;
  }

private:
  sc_dt::sc_uint<16>  feature[6];
  sc_dt::sc_uint<8>   z_crd;
  sc_dt::sc_uint<16>  y_crd;
  sc_dt::sc_uint<16>  x_crd;
};
//}}}

// 定义接口
class PointInterface : public sc_core::sc_interface {
public:
  virtual void send(const PointStruct& point) = 0;
  virtual bool receive(PointStruct& point) = 0;
};

// Consumer 实现接口
class PointChannel : public PointInterface {
public:
  PointChannel() : point_available(false) {}

  void send(const PointStruct& point) override {
    while (point_available) {
      wait(write_event); // 如果消费者还没消费，阻塞生产者
    }
    this->point = point;
    point_available = true;
    read_event.notify(); // 通知消费者
  }

  bool receive(PointStruct& point) override {
    while (!point_available) {
      wait(read_event); // 如果生产者没有生成，阻塞消费者
    }
    point = this->point;
    point_available = false;
    write_event.notify(); // 通知生产者可以写
    return true;
  }

private:
  PointStruct point;
  bool point_available;
  sc_core::sc_event write_event, read_event;
};

SC_MODULE(Producer) {
  //sc_core::sc_port<sc_core::sc_fifo_out_if<PointStruct> > out;
  sc_core::sc_port<PointInterface> out;

  SC_CTOR(Producer) {
    SC_THREAD(produce);
  }

  void produce() {
    for (int i = 0; i < 10; ++i) {
      PointStruct point(i, i * 2, i * 3);
      for (int j = 0; j < 6; ++j) {
        point.setFeature(j, i * 10 + j);
      }
      std::cout << "Producer: Sending PointStruct " << i << std::endl;
      out->send(point);
    }
  }
};

SC_MODULE(Consumer) {
  //sc_core::sc_port<sc_core::sc_fifo_in_if<PointStruct> > in;
  sc_core::sc_port<PointInterface> in;

  SC_CTOR(Consumer) {
    SC_THREAD(consume);
  }

  void consume() {
    for (int i = 0; i < 10; ++i) {
      PointStruct point;
      in->receive(point);
      std::cout << "Consumer: Received PointStruct " << i << std::endl;
      point.print();
    }
  }
};

int sc_main(int argc, char* argv[]) {
  sc_core::sc_fifo<PointStruct> fifo(10); // FIFO 缓冲区

  Producer producer("Producer");
  Consumer consumer("Consumer");

  producer.out(fifo);
  consumer.in(fifo);

  sc_core::sc_start();

  return 0;
}
